use std::collections::HashMap;
//处理 http 请求
#[derive(Debug,PartialEq)]
pub enum Method{
    Get,
    Post,
    Uninitialized,
}

//为Method 实现From trait 将字符串切片转化成Method类型
impl From<&str> for Method{
    fn from(s:&str)->Method{
        match s{
            "GET"=>Method::Get,
            "POST"=>Method::Post,
            _=>Method::Uninitialized,
        }
    }
}


#[derive(Debug,PartialEq)]  //在Version上面还得声明 Version 要实现的trait，文件开头写的是Method的声明
pub enum Version{
    V1_1,
    V2_0,
    Uninitialized,
}
//为Version 枚举实现from trait
impl From<&str> for Version{
    fn from(s:&str)->Version{
        match s{
            "HTTP/1.1"=>Version::V1_1,
            _=>Version::Uninitialized,
        }
    }
}

#[derive(Debug,PartialEq)]
pub enum Resource{
    Path(String),
}

#[derive(Debug)]  //单独写出来会报错，后面必须有enum struct union
pub struct HttpRequest{
    pub method:Method,
    pub version:Version,
    pub resource:Resource,
    pub headers:HashMap<String,String>,//k,v 类型
    pub msg_body:String,
}
impl From<String> for HttpRequest{
    fn from(req:String)->Self{//返回 HttpRequest 对象
        let mut parsed_mothod=Method::Uninitialized;
        let mut parsed_version=Version::V1_1;
        let mut parsed_resource=Resource::Path("".to_string());
        let mut parsed_headers=HashMap::new();
        let mut parsed_msg_body="";

        for line in req.lines(){
            if line.contains("HTTP"){
                //说明是请求行
                let (method,resource,version)=process_req_line(line);
                parsed_mothod=method;
                parsed_resource=resource;
                parsed_version=version;
            }else if line.contains(":"){
                let (key,value)=process_header_line(line);
                parsed_headers.insert(key, value);
            }else if line.len()==0{
                //空行
            }else {
                parsed_msg_body=line;//消息主体
            }
        }
            HttpRequest{
                method:parsed_mothod,
                version:parsed_version,
                resource:parsed_resource,
                headers:parsed_headers,
                msg_body:parsed_msg_body.to_string(),
        }
    }
}


//输入字符串切片 返回解析到的 Method Resource Version
fn process_req_line(s:&str)->(Method,Resource,Version){
    let mut words=s.split_whitespace();
    let method=words.next().unwrap();
    let resource=words.next().unwrap();
    let version=words.next().unwrap();
    (
        method.into(),//method 还是字符串切片 需要into 转化成Method 枚举类型

        //Resource 类型需要自己构造
        Resource::Path(resource.to_string()),
        version.into(),
    )
}
fn process_header_line(s:&str)->(String,String){
    let mut header_items=s.split(":");
    let mut key=String::from("");
    let mut value=String::from(":");
    //next 第一次返回的是key 第二次返回的是value
    //if let Some() 去匹配返回的数据，不为空再去给key value赋值
    if let Some(k)=header_items.next(){
        key=k.to_string();
    }
    if let Some(v)=header_items.next(){
        value=v.to_string();
    }
    //根据函数返回值 去将解析好的数据 包裹后返回
    (key,value)
}
//cargo test -p http 测试http 包中的test
#[cfg(test)]
mod tests{
    use super::*;
    #[test]
    fn test_method_into(){
        let m:Method="GET".into();//实现了From trait，就可以用into方法
        assert_eq!(m,Method::Get);//字符串调用into 是否等于枚举中的Get
    }
    #[test]
    fn test_version_into(){
        let v:Version="HTTP/1.1".into();
        assert_eq!(v,Version::V1_1);
    }
}